package top.hcode.hoj.tyedu;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import lombok.RequiredArgsConstructor;
import org.nutz.lang.util.NutMap;
import org.springframework.stereotype.Component;
import top.hcode.hoj.common.LazyDao;
import top.hcode.hoj.pojo.entity.org.TyOrg;
import top.hcode.hoj.pojo.entity.org.Org;
import top.hcode.hoj.utils.CommonMethods;
import top.hcode.hoj.utils.Constants;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 同步学校组织结构
 * @author orangej
 * @since 2025/1/23
 */
@Component
@RequiredArgsConstructor
public class SyncSchoolOrgService {
    private final LazyDao lazyDao;
    private final TyGatewayClient client;

    public void syncSchool(String orgId) {
        TyOrg school = lazyDao.selectOne(TyOrg.class, "select * from ty_org where id = ?", orgId);

        String rootCode = school.getTreeCode();
        if (StrUtil.isBlank(rootCode)) {
            throw new RuntimeException(school.getOrgName() + " 的 treeCode 为空");
        }
        if (rootCode.trim().length() != 4) {
            throw new RuntimeException(school.getOrgName() + " 的 treeCode 长度错误 : " + rootCode);
        }

        List<TyOrg> tyOrgList = client.getEduChild(orgId);
        tyOrgList.add(school);

        clearSubOrgOf(rootCode);        // 删除原来的结构（保留校区信息）
        sortTyOrgList(tyOrgList);       // 对 orgList 进行排序，排序字段为 orgType、displayOrder
        updateTreeCode(tyOrgList);      // 设置 treeCode，当前code为父节点的code + 当前节点的4位顺序号
        saveTyOrgList(tyOrgList);       // 保存 ty_org
        saveOrgList(tyOrgList);         // 保存 org
    }

    private void clearSubOrgOf(String rootCode) {
        lazyDao.runSql("delete from ty_org where tree_code like '" + rootCode + "%' and org_type > 3");
    }

    public void saveOrgList(List<TyOrg> tyOrgList) {
        Map<String, String> tyOrgIdMap = lazyDao.selectList(Org.class, "select * from org where ty_org_id in (?)", tyOrgList.stream().map(TyOrg::getId).collect(Collectors.toList()))
                .stream().collect(Collectors.toMap(Org::getTyOrgId, Org::getId));

        List<Org> orgList = new ArrayList<>();
        Date now = new Date();
        for (TyOrg tyOrg : tyOrgList) {
            Org org = new Org();

            String tyOrgId = tyOrg.getId();
            String id = tyOrgIdMap.get(tyOrgId);

            if (id == null) {
                id = IdWorker.getIdStr();
                tyOrgIdMap.put(tyOrgId, id);
                org.setGmtCreate(now);  // gmt_create 新记录
            }

            org.setId(id);
            org.setOrgName(tyOrg.getOrgName());
            org.setOrgType(tyOrg.getOrgType());
            org.setParentId(tyOrgIdMap.get(tyOrg.getParentId()));
            org.setTreeCode(tyOrg.getTreeCode());
            org.setTyOrgId(tyOrgId);
            if (Constants.OrgType.GRADE.getType().equals(tyOrg.getOrgType())) {
                // 设置年级编号
                org.setGradeNum(Constants.GradeNum.parseGradeNum(tyOrg.getOrgName()));
            }
            if (Constants.OrgType.CLASS.getType().equals(tyOrg.getOrgType())) {
                // 设置年级和班级编号
                orgList.stream()
                        .filter(o -> o.getId().equals(org.getParentId()))
                        .findFirst().ifPresent(parentOrg -> org.setGradeNum(parentOrg.getGradeNum()));
                org.setClassNum(CommonMethods.parseClassNum(tyOrg.getOrgName()));
            }

            org.setGmtModified(now);
            orgList.add(org);
        }

        // save to db
        orgList.parallelStream().forEach(org -> {
            NutMap columns = CommonMethods.obj2HumpMap(org);
            if (org.getGmtCreate() != null) {
                lazyDao.insert("org", columns);
            } else {
                columns.remove("gmt_create");
                lazyDao.update("org", columns, "id = :id");
            }
        });
    }

    private void updateTreeCode(List<TyOrg> orgList) {
        Map<String, Integer> childNumMap = new HashMap<>();

        // 设置 treeCode，当前code为父节点的code + 当前节点的4位顺序号
        orgList.forEach(org -> {
            TyOrg parent = orgList.stream().filter(o -> o.getId().equals(org.getParentId())).findFirst().orElse(null);
            if (parent != null) {
                String parentCode = parent.getTreeCode();
                int childNum = childNumMap.getOrDefault(parentCode, 1);
                String code = parentCode + String.format("%04d", childNum);
                org.setTreeCode(code);
                childNumMap.put(parentCode, (childNum + 1));
            }
        });
    }

    private void sortTyOrgList(List<TyOrg> orgList) {
        // 对 orgList 进行排序，排序字段为 orgType、displayOrder
        orgList.sort((o1, o2) -> {
            if (!Objects.equals(o1.getOrgType(), o2.getOrgType())) {
                return o1.getOrgType() - o2.getOrgType();
            }
            return o1.getDisplayOrder().compareTo(o2.getDisplayOrder());
        });
    }

    private void saveTyOrgList(List<TyOrg> orgList) {
        orgList.parallelStream().forEach(org -> {
            org.setGmtCreate(new Date());
            org.setGmtModified(new Date());
            TyOrg dbo = lazyDao.selectOne(TyOrg.class, "select * from ty_org where id = ?", org.getId());
            if (dbo == null) {
                lazyDao.runSql("insert into ty_org (id, org_name, org_type, parent_id, tree_code, display_order, gmt_create, gmt_modified) values (?, ?, ?, ?, ?, ?, ?, ?)",
                        org.getId(), org.getOrgName(), org.getOrgType(), org.getParentId(), org.getTreeCode(), org.getDisplayOrder(), org.getGmtCreate(), org.getGmtModified());
            } else if (org.getOrgType() > 3) {
                // 学校和校区的名字不改
                lazyDao.runSql("update ty_org set org_name = ?, org_type = ?, parent_id = ?, tree_code = ?, display_order = ?, gmt_modified = ? where id = ?",
                        org.getOrgName(), org.getOrgType(), org.getParentId(), org.getTreeCode(), org.getDisplayOrder(), org.getGmtModified(), org.getId());
            }
        });
    }

}
